package myjwt

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	v1 "mindonmap/api/v1"
	v4 "mindonmap/api/v4"
	"mindonmap/models"
	"mindonmap/pkgs/e"
	"mindonmap/pkgs/setting"
	"net/http"
	"strconv"

	jwt "github.com/appleboy/gin-jwt/v2"
	"github.com/gin-gonic/gin"

	"strings"
	"time"
)

type Mainloginsform struct {
	Tid   string `json:"t_id"`
	Token string `json:"token"`
	Eid   string `json:"e_id"`
	Error int    `json:"error"`
}

var identityKey = setting.IdentityKey
var httpstatus = 500

func GinJWTMiddlewareLogin(jwtAuthorizator IAuthorizator) (authMiddleware *jwt.GinJWTMiddleware) {
	authMiddleware, err := jwt.New(&jwt.GinJWTMiddleware{
		Realm:       "zone",
		Key:         []byte("mind"), // 用于签名的密钥。必需的。
		Timeout:     time.Minute * 3600,
		MaxRefresh:  time.Hour * 60,
		IdentityKey: identityKey,
		PayloadFunc: func(data interface{}) jwt.MapClaims {
			v, ok := data.(models.User)
			if ok {

				// 根据用户名获取角色
				return jwt.MapClaims{
					"userId":   v.UserId,
					"username": v.UserName,
					"token":    v.Token,
				}
			}
			return jwt.MapClaims{}
		},
		IdentityHandler: func(c *gin.Context) interface{} {
			claims := jwt.ExtractClaims(c)
			_, ok := claims["token"].(string)
			if !ok {
				return jwt.ErrMissingLoginValues
			}
			// 设置角色
			return &models.User{
				UserName: claims["username"].(string),
				UserId:   claims["userId"].(string),
				Token:    claims["token"].(string),
			}
		},

		Authenticator: func(c *gin.Context) (interface{}, error) {
			// 处理登录逻辑。 成功时调用 LoginResponse，失败时调用 Unauthorized
			// 提交参数处理
			var jsons v1.LoginsFormInfo
			if err := c.ShouldBind(&jsons); err != nil {
				return "", errors.New("parameter cannot be empty")
			}

			v := "email=" + jsons.Email + "&password=" + jsons.Password + "&e_id=" + jsons.EId
			baseurl := setting.GetLoginurl() + "/account/email/login"
			responseToken, _ := http.Post(baseurl, "application/x-www-form-urlencoded", strings.NewReader(v))

			defer responseToken.Body.Close()
			body, err := ioutil.ReadAll(responseToken.Body)
			if err != nil {
				httpstatus = e.ERROR_PASS
				return nil, jwt.ErrMissingLoginValues
			}
			var loginvals Mainloginsform
			if err = json.Unmarshal(body, &loginvals); err != nil {
				return "", err
			}
			if loginvals.Error != 0 {
				return nil, jwt.ErrMissingLoginValues
			}
			tId, _ := strconv.Atoi(loginvals.Tid)
			token := loginvals.Token
			eID := jsons.EId

			var userInfo models.User
			userInfo.UserId = strconv.Itoa(tId)
			userInfo.Token = "t_id=" + loginvals.Tid + "&e_id=" + eID + "&token=" + token
			url := c.Request.URL.Path
			if strings.HasPrefix(url, "/v4") {
				// /v4开头,v4版本
				// 更新订阅信息
				v4.SubscriptionStatus(c, userInfo.Token)
			} else if strings.HasPrefix(url, "/v1") {
				// /v1开头,v1版本
			}
			res, typeinfo := checkAuthPlatform(tId, eID, token)
			if typeinfo == 0 {
				userInfo.UserName = res.Email
				userInfo.Avatar = res.Picture
			}

			return userInfo, nil

		},
		//identity 接收标识并处理授权逻辑
		Authorizator: jwtAuthorizator.HandleAuthorizator,
		//handles unauthorized logic
		Unauthorized: func(c *gin.Context, code int, message string) {
			c.JSON(code, gin.H{
				"code":    httpstatus,
				"message": message,
			})
		},

		// TokenLookup is a string in the form of "<source>:<name>" that is used
		// to extract token from the request.
		// Optional. Default value "header:Authorization".
		//Possible values:
		//- "header:<name>"
		// - "query:<name>"
		// - "cookie:<name>"
		// - "param:<name>"
		TokenLookup: "header: Authorization",
		// TokenLookup: "query:token",
		// TokenLookup: "cookie:token",

		// TokenHeadName 头部中的字符串。 默认值为“Bearer”
		TokenHeadName: "Bearer",

		// TimeFunc provides the current time. You can override it to use another time value. This is useful for testing or if your server uses a different time zone than your tokens.
		TimeFunc: time.Now,
	})

	if err != nil {
		log.Fatal("JWT Error:" + err.Error())
	}
	return
}

func GinJWTMiddlewareInit(jwtAuthorizator IAuthorizator) (authMiddleware *jwt.GinJWTMiddleware) {
	authMiddleware, err := jwt.New(&jwt.GinJWTMiddleware{
		Realm:       "zone",
		Key:         []byte("mind"), // 用于签名的密钥。必需的。
		Timeout:     time.Minute * 3600,
		MaxRefresh:  time.Hour * 60,
		IdentityKey: identityKey,
		PayloadFunc: func(data interface{}) jwt.MapClaims {
			v, ok := data.(models.User)
			if ok {
				// 根据用户名获取角色
				return jwt.MapClaims{
					"userId":   v.UserId,
					"username": v.UserName,
					"token":    v.Token,
				}
			}
			// fmt.Print("1。PayloadFunc回调了", v)
			return jwt.MapClaims{}
		},
		IdentityHandler: func(c *gin.Context) interface{} {
			claims := jwt.ExtractClaims(c)
			// 设置角色
			_, ok := claims["token"].(string)
			if !ok {
				return jwt.ErrMissingLoginValues
			}

			return &models.User{
				UserName: claims["username"].(string),
				UserId:   claims["userId"].(string),
				Token:    claims["token"].(string),
			}
		},
		Authenticator: func(c *gin.Context) (interface{}, error) {
			// 处理登录逻辑。 成功时调用 LoginResponse，失败时调用 Unauthorized
			// 提交参数处理
			var loginvals models.MainPlatform
			if err := c.ShouldBind(&loginvals); err != nil {
				fmt.Println(err)
				return "", errors.New("parameter cannot be empty")
			}
			tId := loginvals.Tid
			token := loginvals.Token
			eID := loginvals.Eid

			fmt.Println("自动登录，存储session：", loginvals)

			url := c.Request.URL.Path
			if strings.HasPrefix(url, "/v4") {
				// /v4开头,v4版本
				// 更新订阅信息
				v4.SubscriptionStatus(c, "t_id="+strconv.Itoa(tId)+"&e_id="+eID+"&token="+token)
			} else if strings.HasPrefix(url, "/v1") {
				// /v1开头,v1版本
			}

			fmt.Println("获取用户信息图像")
			//获取用户信息图像
			res, err := checkAuthPlatform(tId, eID, token)
			if err == 0 {
				return models.User{
					UserId:   strconv.Itoa(int(tId)),
					UserName: res.Email,
					Token:    "t_id=" + strconv.Itoa(tId) + "&e_id=" + eID + "&token=" + token,
					Avatar:   res.Picture,
				}, nil
			}

			httpstatus = int(err)
			return nil, jwt.ErrMissingLoginValues

		},
		//identity 接收标识并处理授权逻辑
		Authorizator: jwtAuthorizator.HandleAuthorizator,
		//handles unauthorized logic
		Unauthorized: func(c *gin.Context, code int, message string) {
			c.JSON(code, gin.H{
				"code":    httpstatus,
				"message": message,
			})
		},
		// TokenLookup is a string in the form of "<source>:<name>" that is used
		// to extract token from the request.
		// Optional. Default value "header:Authorization".
		//Possible values:
		//- "header:<name>"
		// - "query:<name>"
		// - "cookie:<name>"
		// - "param:<name>"
		TokenLookup: "header: Authorization",
		// TokenLookup: "query:token",
		// TokenLookup: "cookie:token",

		// TokenHeadName 头部中的字符串。 默认值为“Bearer”
		TokenHeadName: "Bearer",

		// TimeFunc provides the current time. You can override it to use another time value. This is useful for testing or if your server uses a different time zone than your tokens.
		TimeFunc: time.Now,
	})

	if err != nil {
		// fmt.Print("log回调了")
		fmt.Print("JWT Error:" + err.Error())
	}
	return
}

func checkAuthPlatform(tid int, eid string, token string) (models.Webinfo, float64) {

	// curl
	v := "t_id=" + strconv.Itoa(tid) + "&e_id=" + eid + "&token=" + token

	baseurl := setting.GetLoginurl() + "/account/profile"
	client := &http.Client{Timeout: 60 * time.Second}
	responseToken, err := client.Post(baseurl, "application/x-www-form-urlencoded", strings.NewReader(v))
	if err != nil {
		fmt.Println(err)
	}
	defer responseToken.Body.Close()

	body, err := ioutil.ReadAll(responseToken.Body)
	models.SaveUserLog(tid, time.Now().Unix(), 0)
	fmt.Print("curl回调了")
	if err != nil {
		fmt.Println(err)
	}

	var data models.Webinfo
	err = json.Unmarshal(body, &data)
	if err != nil {
		return data, 0
	}
	res := data.Error
	fmt.Print(res)
	if res == 0 {
		return data, res
	}
	return data, res
}
